/******************************************************************/
/*                                                                */
/*  Winpooch : Windows Watchdog                                   */
/*  Copyright (C) 2004-2005  Benoit Blanchon                      */
/*                                                                */
/*  This program is free software; you can redistribute it        */
/*  and/or modify it under the terms of the GNU General Public    */
/*  License as published by the Free Software Foundation; either  */
/*  version 2 of the License, or (at your option) any later       */
/*  version.                                                      */
/*                                                                */
/*  This program is distributed in the hope that it will be       */
/*  useful, but WITHOUT ANY WARRANTY; without even the implied    */
/*  warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR       */
/*  PURPOSE.  See the GNU General Public License for more         */
/*  details.                                                      */
/*                                                                */
/*  You should have received a copy of the GNU General Public     */
/*  License along with this program; if not, write to the Free    */
/*  Software Foundation, Inc.,                                    */
/*  675 Mass Ave, Cambridge, MA 02139, USA.                       */
/*                                                                */
/******************************************************************/

// standard headers
#include <shlobj.h>
#include <windows.h>
#include <commctrl.h>

// project's headers
#include "Assert.h"
#include "Alert.h"
#include "Config.h"
#include "ConfigDlg.h"
#include "DirWatcher.h"
#include "HistoryWnd.h"
#include "Language.h"
#include "Log.h"
#include "MainWindow.h"
#include "RegWatcher.h"
#include "UpdWatcher.h"
#include "Version.h"

// check if we use unicode
#ifndef UNICODE
#warning Compiling without using UNICODE
#endif
#ifndef _UNICODE
#warning Compiling without using _UNICODE
#endif
  

#define DIRWATCHERS  18

#define REGWATCHERS  70



int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
		    LPSTR lpCmdLine, int nCmdShow)
{
  int		i ;
  MSG		msg ;
  HWND		hwnd ;
  HANDLE	hMutex ;
  HDIRWATCHER	aDirWatch[DIRWATCHERS] ;
  HREGWATCHER	aRegWatch[REGWATCHERS] ;
  HUPDWATCHER	hUpdWatch ;
  OSVERSIONINFO	osInfo = { sizeof(OSVERSIONINFO) } ;
  
  // check OS version, should be NT
  GetVersionEx (&osInfo) ;
  if( osInfo.dwPlatformId != VER_PLATFORM_WIN32_NT )
    {
      MessageBox (NULL, TEXT("This program requires Microsoft Windows NT, 2000, XP or higher"), 
		  TEXT(APPLICATION_NAME), MB_ICONERROR) ;
      return 1 ;
    }

  // init config module
  Config_Init () ;

  // init language module
  if( ! Language_Init() )
    {
      MessageBox (NULL, TEXT("Failed to initialize language module"),
		  TEXT(APPLICATION_NAME), MB_ICONERROR) ;
      goto failed ;
    } 

  // set mutex to avoid multiple instance
  hMutex = CreateMutex (NULL, TRUE, TEXT(APPLICATION_NAME)) ;

  // an instance is already running ?
  if( GetLastError()!=0 )
    {
      MessageBox (NULL, STR(_ALREADY_RUNNING), 
		  TEXT(APPLICATION_NAME), MB_ICONERROR) ;
      goto failed ;
    }
  
  // init log module
  if( ! Log_Init(APPLICATION_NAME TEXT(".log"),
		 Config_GetInteger(CFGINT_MAX_LOG_SIZE)) )
    {
      MessageBox (NULL, TEXT("Failed to initialize log module"),
		  TEXT(APPLICATION_NAME), MB_ICONERROR) ;
      goto failed ;
    } 

  // init common controls (balloon, ListView, etc.)
  InitCommonControls() ;

  // register classes
  if( ! MainWnd_RegisterClass (hInstance) ||
      ! HistoryWnd_RegisterClass (hInstance) )
    {
      MessageBox (NULL, TEXT("Failed to register window class"),
		  TEXT(APPLICATION_NAME), MB_ICONERROR) ;
      goto failed ;
    } 

  // create main window
  hwnd = MainWnd_CreateWindow (hInstance) ;

  // set hwnd to receive WM_LANGUAGECHANGED
  Language_SetHwnd (hwnd) ;

  // init alert module
  if( ! Alert_Init (hwnd) )
    {
      MessageBox (NULL, TEXT("Failed to initialize alert module"),
		  TEXT(APPLICATION_NAME), MB_ICONERROR) ;
      goto failed ;
    }

  // add update watcher
  hUpdWatch = UpdWatcher_New () ;
  
  // add dir watchers
  i = 0 ;
  aDirWatch[i++] = DirWatcher_NewByCSIDL	(CSIDL_SYSTEM,	NULL,	FALSE, ADVICE_DIR_SYSTEM) ;
  aDirWatch[i++] = DirWatcher_NewByCSIDL	(CSIDL_COMMON_STARTUP,	NULL,	FALSE, ADVICE_DIR_STARTUP) ;
  aDirWatch[i++] = DirWatcher_NewByCSIDL	(CSIDL_STARTUP,	NULL,	FALSE, ADVICE_DIR_STARTUP) ;
  aDirWatch[i++] = DirWatcher_NewByCSIDLAndSubDir (CSIDL_SYSTEM, TEXT("drivers\\etc"), NULL, FALSE, ADVICE_DIR_NET_CONFIG) ;
  aDirWatch[i++] = DirWatcher_NewByPath		(TEXT("C:"),	TEXT("explorer.exe"),	FALSE, ADVICE_DIR_MASK) ;
  aDirWatch[i++] = DirWatcher_NewByCSIDL	(CSIDL_WINDOWS,	TEXT("system.ini"),	FALSE, ADVICE_DIR_WINDOWS_CONFIG) ;
  aDirWatch[i++] = DirWatcher_NewByCSIDL	(CSIDL_WINDOWS,	TEXT("win.ini"),	FALSE, ADVICE_DIR_WINDOWS_CONFIG) ;
  aDirWatch[i++] = DirWatcher_NewByPath		(TEXT("C:"),	TEXT("autoexec.bat"),	FALSE, ADVICE_DIR_WINDOWS_CONFIG) ;
  aDirWatch[i++] = DirWatcher_NewByPath		(TEXT("C:"),	TEXT("boot.ini"),	FALSE, ADVICE_DIR_WINDOWS_CONFIG) ;
  aDirWatch[i++] = DirWatcher_NewByPath		(TEXT("C:"),	TEXT("config.sys"),	FALSE, ADVICE_DIR_WINDOWS_CONFIG) ;
  aDirWatch[i++] = DirWatcher_NewByPath		(TEXT("C:"),	TEXT("ntdetect.com"),	FALSE, ADVICE_DIR_SYSTEM_APPLICATION) ;
  aDirWatch[i++] = DirWatcher_NewByPath		(TEXT("C:"),	TEXT("ntldr"),		FALSE, ADVICE_DIR_SYSTEM_APPLICATION) ;
  aDirWatch[i++] = DirWatcher_NewByCSIDL	(CSIDL_WINDOWS,	TEXT("winstart.bat"),	FALSE, ADVICE_NONE) ;
  aDirWatch[i++] = DirWatcher_NewByCSIDL	(CSIDL_WINDOWS,	TEXT("explorer.exe"),	FALSE, ADVICE_DIR_SYSTEM_APPLICATION) ;
  aDirWatch[i++] = DirWatcher_NewByCSIDL	(CSIDL_WINDOWS,	TEXT("taskman.exe"),	FALSE, ADVICE_DIR_SYSTEM_APPLICATION) ;
  aDirWatch[i++] = DirWatcher_NewByCSIDL	(CSIDL_WINDOWS,	TEXT("regedit.exe"),	FALSE, ADVICE_DIR_SYSTEM_APPLICATION) ;
  aDirWatch[i++] = DirWatcher_NewByCSIDL	(CSIDL_WINDOWS,	TEXT("wininit.ini"),	FALSE, ADVICE_DIR_WINDOWS_CONFIG) ;
  aDirWatch[i++] = DirWatcher_NewByCSIDLAndSubDir(CSIDL_WINDOWS, TEXT("Tasks"),	NULL,	TRUE, ADVICE_DIR_TASKS) ;
  ASSERT (i==DIRWATCHERS) ;
    
  // add reg watchers
  i=0 ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Run"), TRUE, ADVICE_REG_RUN) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run"), TRUE, ADVICE_REG_RUN) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\RunEx"), TRUE, ADVICE_REG_RUN) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\RunEx"), TRUE, ADVICE_REG_RUN) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce"), TRUE, ADVICE_REG_RUN) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce"), TRUE, ADVICE_REG_RUN) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\RunOnceEx"), TRUE, ADVICE_REG_RUN) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\RunOnceEx"), TRUE, ADVICE_REG_RUN) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\RunServices"), TRUE, ADVICE_REG_RUN) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\RunServices"), TRUE, ADVICE_REG_RUN) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\RunServicesOnce"), TRUE, ADVICE_REG_RUN) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\RunServicesOnce"), TRUE, ADVICE_REG_RUN) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKLM\\Software\\Microsoft\\Active Setup\\Installed Components"), TRUE, ADVICE_NONE) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows"/*\\AppInit_Dlls"*/), FALSE, ADVICE_NONE) ;
  //aRegWatch[i++] = RegWatcher_New (TEXT("HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\Notify"), TRUE, ADVICE_REG_WINLOGON) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"), TRUE, ADVICE_REG_WINLOGON) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows\\load"), TRUE, ADVICE_REG_RUN) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer\\Run"), TRUE, ADVICE_REG_RUN) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer\\Run"), TRUE, ADVICE_REG_RUN) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\WOW\\boot"), TRUE, ADVICE_NONE) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\IniFileMapping"), TRUE, ADVICE_REG_INIFILEMAPPING) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\explorer\\shell folders"), TRUE, ADVICE_REG_FOLDERMAPPING) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\explorer\\user shell folders"), TRUE, ADVICE_REG_FOLDERMAPPING) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\explorer\\shell folders"), TRUE, ADVICE_REG_FOLDERMAPPING) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\explorer\\user shell folders"), TRUE, ADVICE_REG_FOLDERMAPPING) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved"), TRUE, ADVICE_NONE) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\ShellServiceObjectDelayLoad"), TRUE, ADVICE_NONE) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKCR\\*\\shellex\\contextmenuhandlers"), TRUE, ADVICE_NONE) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKLM\\Software\\CLASSES\\*\\shellex\\contextmenuhandlers"), TRUE, ADVICE_NONE) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKLM\\Software\\Microsoft\\Active Setup\\Installed Components\\*"), FALSE, ADVICE_NONE) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Browser Helper Objects"), TRUE, ADVICE_NONE) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKLM\\Software\\Microsoft\\Command Processor"), FALSE, ADVICE_NONE) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKCU\\Software\\Microsoft\\Command Processor"), FALSE, ADVICE_NONE) ;
  //  aRegWatch[i++] = RegWatcher_New (TEXT("HKCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows"), FALSE, ADVICE_NONE) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKLM\\System\\CurrentControlSet\\Control\\Session Manager\\Environment"), FALSE, ADVICE_NONE) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKLM\\System\\CurrentControlSet\\Control\\Session Manager"), FALSE, ADVICE_NONE) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKLM\\Software\\Microsoft\\ole"), TRUE, ADVICE_REG_EXEASSOCIATION) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKCR\\exefile\\shell\\open\\command"), TRUE, ADVICE_REG_EXEASSOCIATION) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKCR\\exefile\\shell\\runas\\command"), TRUE, ADVICE_REG_EXEASSOCIATION) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKCR\\Folder\\shell\\open\\command"), TRUE, ADVICE_REG_EXEASSOCIATION) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKCR\\Folder\\shell\\explore\\command"), TRUE, ADVICE_REG_EXEASSOCIATION) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKCR\\batfile\\shell\\open\\command"), TRUE, ADVICE_REG_SRCASSOCIATION) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKCR\\comfile\\shell\\open\\command"), TRUE, ADVICE_REG_EXEASSOCIATION) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKCR\\cmdfile\\shell\\open\\command"), TRUE, ADVICE_REG_SRCASSOCIATION) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKCR\\regfile\\shell\\open\\command"), TRUE, ADVICE_REG_SRCASSOCIATION) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKCR\\scrfile\\shell\\open\\command"), TRUE, ADVICE_REG_EXEASSOCIATION) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKCR\\scrfile\\shell\\config\\command"), TRUE, ADVICE_REG_EXEASSOCIATION) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKCR\\vbsfile\\shell\\open\\command"), TRUE, ADVICE_REG_SRCASSOCIATION) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKCR\\vbsfile\\shell\\open2\\command"), TRUE, ADVICE_REG_SRCASSOCIATION) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKCR\\jsfile\\shell\\open\\command"), TRUE, ADVICE_REG_SRCASSOCIATION) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKCR\\jarfile\\shell\\open\\command"), TRUE, ADVICE_REG_EXEASSOCIATION) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKCR\\piffile\\shell\\open\\command"), TRUE, ADVICE_REG_EXEASSOCIATION) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKCR\\htafile\\shell\\open\\command"), TRUE, ADVICE_REG_EXEASSOCIATION) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKCR\\.exe"), TRUE, ADVICE_REG_EXEASSOCIATION) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKCR\\.Folder"), TRUE, ADVICE_REG_EXEASSOCIATION) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKCR\\.bat"), TRUE, ADVICE_REG_SRCASSOCIATION) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKCR\\.com"), TRUE, ADVICE_REG_EXEASSOCIATION) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKCR\\.cmd"), TRUE, ADVICE_REG_SRCASSOCIATION) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKCR\\.reg"), TRUE, ADVICE_REG_SRCASSOCIATION) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKCR\\.scr"), TRUE, ADVICE_REG_EXEASSOCIATION) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKCR\\.vbs"), TRUE, ADVICE_REG_SRCASSOCIATION) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKCR\\.js"), TRUE, ADVICE_REG_SRCASSOCIATION) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKCR\\.jar"), TRUE, ADVICE_REG_EXEASSOCIATION) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKCR\\.pif"), TRUE, ADVICE_REG_EXEASSOCIATION) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKCR\\.hta"), TRUE, ADVICE_REG_EXEASSOCIATION) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKCR\\mailto\\shell\\open\\command"), TRUE, ADVICE_NONE) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKLM\\SYSTEM\\CurrentControlSet\\Control\\WOW"), FALSE, ADVICE_NONE) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKCU\\Control Panel\\Desktop"), FALSE, ADVICE_NONE) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKU\\.DEFAULT\\Control Panel\\Desktop"), FALSE, ADVICE_NONE) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager"), FALSE, ADVICE_NONE) ;  
  aRegWatch[i++] = RegWatcher_New (TEXT("HKCU\\Software\\Microsoft\\Internet Explorer\\Main"), TRUE, ADVICE_NONE) ;
  aRegWatch[i++] = RegWatcher_New (TEXT("HKLM\\Software\\Microsoft\\Internet Explorer\\Main"), TRUE, ADVICE_NONE) ;
  // aRegWatch[i++] = RegWatcher_New (TEXT("HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"), TRUE, ADVICE_NONE) ;
  // aRegWatch[i++] = RegWatcher_New (TEXT("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"), TRUE, ADVICE_NONE) ;
  ASSERT (i==REGWATCHERS) ;

  // log message
  Log_Print (APPLICATION_NAME TEXT(" started")) ;

  // message pump
  while (GetMessage (&msg, NULL, 0, 0))
    {
      if( ConfigDlg_IsItsMessage(&msg) ) continue ;      

      TranslateMessage (&msg) ;
      DispatchMessage (&msg) ;
    }
  
  UpdWatcher_Delete (hUpdWatch) ;
  for( i=0 ; i<REGWATCHERS ; i++ )
    RegWatcher_Delete (aRegWatch[i]) ;
  for( i=0 ; i<DIRWATCHERS ; i++ )
    DirWatcher_Delete (aDirWatch[i]) ;

  // log message
  Log_Print (APPLICATION_NAME TEXT(" stopped")) ;

 failed :

  Alert_Uninit () ;
  Language_Uninit () ;
  Log_Uninit () ;
  Config_Uninit () ;
  CloseHandle (hMutex) ;
  
  return msg.wParam ;
}
